package com.test.mylotterysystem.service.MQ;

import cn.hutool.core.date.DateUtil;
import com.test.mylotterysystem.comment.config.ThreadPoolConfig;
import com.test.mylotterysystem.comment.errorCode.ServiceErrorCode;
import com.test.mylotterysystem.comment.exception.ServiceException;
import com.test.mylotterysystem.comment.utils.JacksonUtil;
import com.test.mylotterysystem.comment.utils.MailUtil;
import com.test.mylotterysystem.comment.utils.SMSUtil;
import com.test.mylotterysystem.constants.Constants;
import com.test.mylotterysystem.controller.Param.DrawPrizeParam;
import com.test.mylotterysystem.dao.DO.ActivityDO;
import com.test.mylotterysystem.dao.DO.ActivityPrizeDO;
import com.test.mylotterysystem.dao.DO.ActivityUserDO;
import com.test.mylotterysystem.dao.DO.WinnerDO;
import com.test.mylotterysystem.dao.Mapper.ActivityMapper;
import com.test.mylotterysystem.dao.Mapper.ActivityPrizeMapper;
import com.test.mylotterysystem.dao.Mapper.ActivityUserMapper;
import com.test.mylotterysystem.dao.Mapper.WinnerMapper;
import com.test.mylotterysystem.service.ActivityStatusChange.ActivityStatusChange;
import com.test.mylotterysystem.service.ActivityStatusChange.Operator.AbstractOperator;
import com.test.mylotterysystem.service.DTO.ConvertActivityStatusDTO;
import com.test.mylotterysystem.service.DrawPrizeService;
import com.test.mylotterysystem.service.serviceEnum.ActivityPrizeStatusEnum;
import com.test.mylotterysystem.service.serviceEnum.ActivityPrizeTiersEnum;
import com.test.mylotterysystem.service.serviceEnum.ActivityStatusEnum;
import com.test.mylotterysystem.service.serviceEnum.ActivityUserStatusEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

@RabbitListener(queues = Constants.QUEUE_NAME)
@Component
@Slf4j
public class RabbitMQListener {

    @Autowired
    private ActivityMapper activityMapper;

    @Autowired
    private ActivityPrizeMapper activityPrizeMapper;

    @Autowired
    private ActivityUserMapper activityUserMapper;

    @Autowired
    private ActivityStatusChange activityStatusChange;

    @Autowired
    private WinnerMapper winnerMapper;

    @Autowired
    private DrawPrizeService drawPrizeService;

    @Resource(name = "asyncServiceExecutor")
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Autowired
    private MailUtil mailUtil;

    @Autowired
    private SMSUtil smsUtil;


    /**
     * 接收rabbitMQ中的数据并进行处理
     *
     * @param map
     */
    @RabbitHandler
    public void handler(Map<String, String> map) {
        if (map.isEmpty()) {
            throw new ServiceException(ServiceErrorCode.RABBIT_MQ_MESSAGE_IS_EMPTY);
        }

        try {
            // 接收数据
            DrawPrizeParam message = JacksonUtil.readValue(map.get("message"), DrawPrizeParam.class);

            // 校验数据
            if (!checkMessage(message)) {
                return;
            }

            // 状态反转(责任链模式 + 策略模式)
            activityStatusChange.convertStatus(message);

            // 存储获奖人员
            List<WinnerDO> winnerDOS = drawPrizeService.saveWinner(message);

            // 发送消息给获奖人员
            sendDrawPrizeMessage(winnerDOS);
        } catch (ServiceException serviceException) {
            log.error("处理 RabbitMQ 时发生异常!", serviceException);
//            rollback(message);
            throw serviceException;
        } catch (Exception exception) {
            log.error("处理 RabbitMQ 时发生异常!", exception);
//            rollback(message);
            throw exception;
        }
    }

    /**
     * 发送消息给获奖人员
     *
     * @param winnerDOS
     */
    private void sendDrawPrizeMessage(List<WinnerDO> winnerDOS) {

        // 发送短息
        threadPoolTaskExecutor.execute(() -> sendMessage(winnerDOS));

        // 发送邮箱
        threadPoolTaskExecutor.execute(() -> sendMail(winnerDOS));
    }

    /**
     * 发送邮箱
     */
    private void sendMail(List<WinnerDO> winnerDOS) {
        if (CollectionUtils.isEmpty(winnerDOS)) {
            log.error("winnerDOS为空，发送邮箱失败");
            return;
        }

        for (WinnerDO winnerDO : winnerDOS) {
            String context = "Hi，" + winnerDO.getWinnerName() + "。恭喜你在"
                    + winnerDO.getActivityName() + "活动中获得"
                    + ActivityPrizeTiersEnum.forName(winnerDO.getPrizeTier())
                    + "：" + winnerDO.getPrizeName() + "。获奖时间为"
                    + DateUtil.formatTime(winnerDO.getWinningTime()) + "，请尽快领 取您的奖励！";

            mailUtil.sendSampleMail(winnerDO.getWinnerEmail(), "中奖信息", context);
        }
    }

    /**
     * 发送短息
     */
    private void sendMessage(List<WinnerDO> winnerDOS) {
        if (CollectionUtils.isEmpty(winnerDOS)) {
            log.error("winnerDOS为空，发送邮箱失败");
            return;
        }

        for (WinnerDO winnerDO : winnerDOS) {
            Map<String, String> map = new HashMap<>();
            map.put("code", "1111");
            smsUtil.sendMessage("SMS_154950909",
                    winnerDO.getWinnerPhoneNumber().getValue(),
                    JacksonUtil.writeValueAsString(map));

        }

    }


    /**
     * 校验传递过来的数据
     *
     * @return
     */
    private boolean checkMessage(DrawPrizeParam message) {
        // 传递过来的数据不为空
        if (message == null) {
            log.error(ServiceErrorCode.RABBIT_MQ_MESSAGE_IS_EMPTY.getErrorMsg());
            return false;
        }

        // 活动没有完成且存在
        ActivityDO activityDO = activityMapper.selectActivityById(message.getActivityId());
        if (activityDO == null) {
            log.error(ServiceErrorCode.ACTIVITY_IS_NOT_EXIST.getErrorMsg());
            return false;
        }
        if (activityDO.getStatus().equalsIgnoreCase(ActivityStatusEnum.FINISH.name())) {
            log.error(ServiceErrorCode.ACTIVITY_STATUS_IS_ERROR.getErrorMsg());
            return false;
        }


        // 人员都是未被抽取的且存在
        List<DrawPrizeParam.Winner> winnerList = message.getWinnerList();
        List<Long> usersId = winnerList.stream().map(DrawPrizeParam.Winner::getUserId).collect(Collectors.toList());
        List<ActivityUserDO> usersResult = activityUserMapper.selectByAUIds(activityDO.getId(), usersId);
        List<Long> usersIds = usersResult.stream().map(ActivityUserDO::getUserId).collect(Collectors.toList());

        for (Long id : usersId) {
            if (!usersIds.contains(id)) {
                log.error(ServiceErrorCode.HAVE_USER_IS_NOT_EXIST.getErrorMsg());
                return false;
            }
        }

        for (ActivityUserDO activityUserDO : usersResult) {
            if (activityUserDO.getStatus().equalsIgnoreCase(ActivityUserStatusEnum.COMPLETE.getStatus())) {
                log.error(ServiceErrorCode.HAVE_USER_STATUS_IS_ERROR.getErrorMsg());
                return false;
            }
        }


        // 奖品都是未被抽取的且存在
        ActivityPrizeDO activityPrizeDO = activityPrizeMapper.selectByAPId(activityDO.getId(), message.getPrizeId());
        if (activityPrizeDO == null) {
            log.error(ServiceErrorCode.PRIZE_IS_NOT_EXIST.getErrorMsg());
            return false;
        }

        if (activityPrizeDO.getStatus().equalsIgnoreCase(ActivityPrizeStatusEnum.COMPLETE.getStatus())) {
            log.error(ServiceErrorCode.PRIZE_STATUS_IS_ERROR.getErrorMsg());
            return false;
        }


        // 中奖者人数是否和设置奖品数量一致
        if (activityPrizeDO.getPrizeAmount() != winnerList.size()) {
            log.error(ServiceErrorCode.PRIZE_AND_USER_NUMBER_IS_NOT_SAME.getErrorMsg());
            return false;
        }

        return true;
    }
}
